home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#41 (Feb 89)
/
Forth code
/
Structures 2.5
< prev
Wrap
Text File
|
1988-12-15
|
15KB
|
561 lines
( STRUCTUREs 2.5 for the Macintosh MACH2 version 2.1 )
( Jan 3, 1987 by Waymen Askey )
( This MACH2 extension is released for the public good; however,
for those planning commercial use of this code, please notify
me so that I might know of its intended use.
Waymen Askey
P.O. Box 901
Vista, Ca 92083
also
GEnie MACH2 RoundTable.)
\ floating point parameters and arrays added by
\ J. Langowski @ MacTutor
only mac also sane also forth definitions
( VARIABLES used in STRUCTURE 2.5 )
decimal
variable current.template
variable op.type
variable A5offset ( holds the A5 offset to a structure )
( CODE word utilities used in STRUCTURE 2.5 )
code var.link ( -- a | variable link pointer )
lea $F7F8(A5),A0
move.l A0,-(A6)
rts
end-code
code a5@ ( -- a )
move.l A5,-(A6)
rts
end-code mach
code get.field ( a1 a2 -- a3 -1 or 0 | searches templates )
( a1=template, a2= pad, a3=field pointer, 0 if not found )
move.l (A6)+,D2
move.l (A6)+,D3
moveq.l #0,D1
moveq.l #0,D0
@start movea.l D3,A1
movea.l D2,A0
move.b (A1)+,D1 ( link to next field )
beq.s @end ( if link=0, field not found )
move.b (A1),D0
@loop cmpm.b (A1)+,(A0)+
dbne D0,@loop
beq.s @found
add.l D1,D3 ( increment field pointer )
bra.s @start
@found movea.l D3,A1
move.b 1(A1),D1 ( get string count )
addq.w #2,D1
btst #0,D1 ( test for odd count )
beq.s @even
addq.w #1,D1
@even add.l D1,D3
moveq.l #-1,D1
move.l D3,-(A6)
@end move.l D1,-(A6)
rts
end-code
code >sr ( n -- | push value onto subroutine stack )
move.l (A6)+,-(A7)
rts
end-code mach
code sr> ( -- n | pop value from subroutine stack )
move.l (A7)+,-(A6)
rts
end-code mach
code sr@ ( -- n | copy value from subroutine stack )
move.l (A7),-(A6)
rts
end-code mach
( Miscellaneous utility words used in STRUCTURE 2.5 )
: >even ( a -- a' | word aligns address, i.e. rounds up to even)
dup 1 and + ;
: >odd ( a -- a' | odd aligns address, rounds up to odd )
1 or ;
: needed ( n -- | checks for at least n items on stack )
depth 1- > abort" Missing needed stack item(s)! " ;
( Brute-force machine code words )
: ncode,
( n1...n -- | machine code defining word, stuffs n words )
create dup needed dup 2* w,
0 do w, loop
does> ( -- | compiles machine code )
dup 2+ swap dup w@ +
do i w@ w, -2 +loop ;
hex
( define some machine code "stuff" words )
41ED 1 ncode, lea_d(a5),a0
4EBA 1 ncode, jsr_d(PC)
4EAD 1 ncode, jsr_d(A5)
( LEA and JSR also need a word of extension for displacement )
2D3C 1 ncode, move.l_#,-(A6) ( plus a long extension for # )
2D08 1 ncode, move.l_a0,-(a6)
4E75 1 ncode, rts,
( The following expect an address to be in A0 )
7000 1010 2D00 3 ncode, byte@
7000 3010 2D00 3 ncode, word@
2D10 1 ncode, long@
201E 1080 2 ncode, byte!
201E 3080 2 ncode, word!
209E 1 ncode, long!
5187 5587 2247 22d8 22d8 32d8 6 ncode, real@
2247 20d9 20d9 30d9 5087 5487 6 ncode, real!
201e e580 2d30 0000 4 ncode, array@
201e e580 219e 0000 4 ncode, array!
201e e380 4281 3230 0000 2d01 6 ncode, warray@
201e e380 221e 3181 0000 5 ncode, warray!
decimal
( Dictionary header, name, and struct link words )
: link>name ( lfa -- 'nf | 'nf points to the header length byte)
4 + ;
: name.count ( 'nf -- 'nf+1 n | dictionary header name count)
count 31 and ;
: link>segment ( lfa -- 'sf | 'sf is the dictionary segment field address)
link>name name.count + >even ;
: link>parameter ( lfa -- 'pf | 'pf is the parameter field pointer)
link>segment 2+ ;
: link>struct ( lfa -- struct.fields )
link>segment 4 + ;
: jsr_d(PC), ( lfa -- | compiles PC relative JSR)
jsr_d(PC)
link>body here - w, ;
: jsr_d(A5), ( lfa -- | compiles A5 relative JSR, i.e. jump table )
jsr_d(A5)
link>parameter w@ w, ;
: struct.zero ( -- lfa | returns lfa of struct.zero )
" struct.zero" find drop ;
: nallot ( n -- | allots n bytes in name space )
np +! ;
: name, ( -- parses and compiles text into name space.)
32 word np @ over c@ 1+ dup >odd nallot cmove ;
: nc, ( n -- | compiles byte into name space )
np @ c! 1 nallot ;
: nw, ( n -- | compiles word into name space )
np @ w! 2 nallot ;
: n, ( n -- | compiles long into name space )
np @ ! 4 nallot ;
( TEMPLATE, STRUCTURE and field words )
: struct.error ( -- )
cr pad count type
." ? Error, unknown field or incomplete structure path! "
abort ;
global
: template ( -- here 0 | begins TEMPLATE definition )
create here 0 2 allot
does> ( -- template.size )
dup w@ swap 4 - body>link current.template ! ;
: tend ( here n -- | (T)emplate(END) ends template definition )
swap w! 0 nw, ;
global
: afield ( size op.type -- )
create w, >even w,
does> ( here Toffset -- here new.Toffset )
( Toffset means (T)emplate(OFFSET) )
2dup 2+ w@ + >sr
w@ np @ >sr 1 nallot name,
0 nc, ( field type=0 ) nc, ( op.type )
nw, ( Toffset ) np @ sr@ - sr> c! ( field link )
sr> ;
( The following op.types are reserved and defined below )
( 06 byte, 12 word, 18 long, 24 string, 30 real, 36 struct,
42 array, 48 warray )
( size.in.bytes op.type AFIELD named.afield.type )
1 06 afield :byte
2 12 afield :word
4 18 afield :long
10 30 afield :real
: :string ( here Toffset size -- here Toffset+size+1 )
3 needed 1+ over + >even swap np @ >sr 1 nallot name,
0 nc, ( field type=0 ) 24 nc, ( op.type=24)
nw, ( Toffset ) np @ sr@ - sr> c! ( field link ) ;
: :array ( here Toffset size -- here Toffset+size+1 )
3 needed 4* over + swap np @ >sr 1 nallot name,
0 nc, ( field type=0 ) 42 nc, ( op.type=42)
nw, ( Toffset ) np @ sr@ - sr> c! ( field link ) ;
: :warray ( here Toffset size -- here Toffset+size+1 )
3 needed 2* over + swap np @ >sr 1 nallot name,
0 nc, ( field type=0 ) 48 nc, ( op.type=48)
nw, ( Toffset ) np @ sr@ - sr> c! ( field link ) ;
: :struct ( here Toffset size -- here Toffset+size )
3 needed over + >even swap np @ >sr 1 nallot name,
06 nc, ( field type=06 ) 36 nc, ( op.type=36 )
nw, ( Toffset )
current.template @ struct.zero - n, ( template link )
np @ sr@ - sr> c! ( field link ) ;
: >pad ( a -- | moves string to pad )
pad over c@ 1+ cmove ;
: make.var.link { | name.pointer var.pointer vlink -- }
np @ -> name.pointer var.link @ -> var.pointer
name.pointer var.link !
name.pointer var.pointer - -> vlink
name.pointer dup 1 and + -> name.pointer
vlink name.pointer !
name.pointer 4 + np ! ;
( Decision table for field type decode )
: do.afield ( ^field.type -- true )
1+ dup c@ op.type ! 1+ w@ A5offset +! -1 ;
: do.bfield ( ^field.type -- new.template false )
dup 1+ dup c@ op.type ! 1+ w@ A5offset +!
4 + @ struct.zero + link>struct 0 ;
: rts rts, ; immediate
( DO.FIELD table entries decode field data )
( afield's are simple :BYTE, :WORD, :LONG, :STRING types )
( bfield's are :STRUCT fields )
create do.field ( field_type table_offset/type )
] do.afield rts ( afield 0 )
do.bfield rts ( bfield 6 )
[ ( end of current table )
global
: make.struct ( template.link A5offset -- )
( This is the word which must resolve a structure reference. )
A5offset ! ( A5 displacement for the struct )
36 op.type ! ( set default op.type to struct )
struct.zero + link>struct ( template.address -- )
begin
32 word >pad
pad get.field
if ( field found )
dup c@ do.field + execute
else ( field not found )
pad find 1 =
if
link>body execute -1
else
struct.error
then
then
until ;
hex
: structure
( n -- | creates structure alloting n bytes in variable space )
1 needed create immediate make.var.link
-4 allot lea_d(a5),a0 vp @ w, ( variable-like beginning )
move.l_#,-(A6) current.template @ struct.zero - ,
move.l_#,-(A6) vp @ ,
" make.struct" find drop dup link>segment w@ 0=
if jsr_d(PC), else jsr_d(A5), then
rts,
vallot ;
decimal
( STRUCTURE operators )
: compileA5 ( -- | compiles A5 reference )
lea_d(a5),a0 a5offset @ w, ;
: pushA5 ( -- | executes A5 var reference )
a5offset @ a5@ + ;
: do.bit ( -- ) ( I'm lazy, define your own. W. Askey )
cr ." BIT operations are yet undefined!" abort ;
: do.struct ( -- ) ( Fetch/store doesn't make sense here. )
cr ." STRUCTURE fetch/store operations are undefined! " abort ;
: do.string ( -- ) ( If you wish, define your own. )
cr ." STRING fetch/store operations are undefined! " abort ;
: do.byte@ ( f -- )
if
compileA5 byte@
else
pushA5 c@
then ;
: do.word@ ( f -- )
if
compileA5 word@
else
pushA5 w@
then ;
: do.long@ ( f -- )
if
compileA5 long@
else
pushA5 @
then ;
: do.array@ ( idx f -- )
if
compileA5 array@
else
4* pushA5 + @
then ;
: do.warray@ ( idx f -- )
if
compileA5 warray@
else
2* pushA5 + w@
then ;
: do.real@ ( f -- )
if
compileA5 real@
else
pushA5 f@
then ;
( Decision table for fetch )
create op.table@ ( op.types are offsets into this table )
] do.bit rts ( op.type = 0 )
do.byte@ rts ( " " = 6 )
do.word@ rts ( " " = 12 )
do.long@ rts ( " " = 18 etc, etc. )
do.string rts
do.real@ rts
do.struct rts
do.array@ rts
do.warray@ rts
[
: do.byte! ( f -- )
if
compileA5 byte!
else
pushA5 c!
then ;
: do.word! ( f -- )
if
compileA5 word!
else
pushA5 w!
then ;
: do.long! ( f -- )
if
compileA5 long!
else
pushA5 !
then ;
: do.array! ( idx f -- )
if
compileA5 array!
else
4* pushA5 + !
then ;
: do.warray! ( idx f -- )
if
compileA5 warray!
else
2* pushA5 + w!
then ;
: do.real! ( f -- )
if
compileA5 real!
else
pushA5 f!
then ;
create op.table! ( decision table for store )
] do.bit rts
do.byte! rts
do.word! rts
do.long! rts
do.string rts
do.real! rts
do.struct rts
do.array! rts
do.warray! rts
[
: s^ ( -- a | returns pointer to structure field )
( ALL field types are allowed. i.e. strings, struct, etc. )
state @
if
compileA5 move.l_a0,-(a6)
else
pushA5
then ; immediate
: s@ ( -- data | Fetch field contents, data type smart)
state @
op.type @ op.table@ + execute ; immediate
: s! ( data -- | Store into field, data type smart)
state @
op.type @ op.table! + execute ; immediate
: stype ( -- op.type | returns the op.type of a field )
op.type @ state @
if
[compile] literal
then ; immediate
( Examples of structure usage. Data Storage is limited to
the approximately 32K global area referenced off of
register A5 -- just as for regular MACH2 variables.
Structure references have a REQUIRED syntax, it is best
NOT to use any non-STRUCTURE Forth words when between field
names in a structure calling sequence. That is, please end
each structure reference prior to any DUP's, SWAP's, etc.
The structure pointer operator -- S^ -- may be used at any
place in the structure calling sequence. S^ will return the
address of the field or structure itself. Structures MUST
be terminated with a defined structure operator! The defined
operators in this upload are S^, S@, S!, and STYPE.
WARNING, if you forget to terminate a structure, no
structure reference will be compiled and an error message MAY
NOT be given. Remember also that field names ARE CASE
SENSITIVE and LOCAL to the structure template. Last comment,
structures MAY be nested to any level. )
fp
template Point
:word x
:word y
tend
template Rect
:word top
:word left
:word bottom
:word right
tend ( TEND ends template definition )
\ example for FP parameters
template parameter
30 :string name
:real value
30 :string unit
tend
template measurement
:long date \ in internal Mac format
80 :string title
255 :string descriptor
parameter :struct wavelength
parameter :struct temperature
parameter :struct angle
256 :array time
256 :array counts
tend
measurement structure curve1
: testarray
100 0 do i 4* i curve1 time s! loop
100 0 do i curve1 time s@ . cr loop
;
: .date ( DateTime DateForm ) { | [ 40 lallot ] mydate -- }
8 shift ^ mydate call IUDateString ^ mydate count type
;
: read.int
begin
pad 1+ 80 expect span @ pad c! pad number? not while
drop cr ." Illegal number [integer], reenter - "
repeat
;
: read.float
begin
pad 1+ 80 expect span @ pad c! pad fnumber? not while
fdrop cr ." Illegal number [float], reenter - "
repeat
;
: setup.curve1 { | dattim -- }
^ dattim call readdatetime drop @
cr ." Today is " 1 .date
cr ." Setting up parameters for curve 1."
dattim curve1 date s!
" lambda" dup c@ 1+ curve1 wavelength name s^ swap cmove
" T" dup c@ 1+ curve1 temperature name s^ swap cmove
" delta" dup c@ 1+ curve1 angle name s^ swap cmove
" [nm]" dup c@ 1+ curve1 wavelength unit s^ swap cmove
" [K]" dup c@ 1+ curve1 temperature unit s^ swap cmove
" [°]" dup c@ 1+ curve1 angle unit s^ swap cmove
cr ." Title (one line) - " cr pad 80 expect
span @ curve1 title s^ c!
pad curve1 title s^ 1+ span @ cmove
cr ." Description (one line) - " cr pad 80 expect
span @ curve1 descriptor s^ c!
pad curve1 descriptor s^ 1+ span @ cmove
cr ." lambda [nm] - " read.float curve1 wavelength value s!
cr ." T [K] - " read.float curve1 temperature value s!
cr ." delta [°] - " read.float curve1 angle value s!
\ example setup of 'measurement data'
20 0 do
i i curve1 time s!
i 100 * i curve1 counts s!
loop
cr ." End setup --- " cr
;
: dump.curve1 { | [ 80 lallot ] mydate -- }
cr ." Data taken on " curve1 date s@ 1 .date
cr curve1 title s^ count type
cr curve1 descriptor s^ count type
cr curve1 wavelength name s^ count type ." = "
curve1 wavelength value s@ f.
curve1 wavelength unit s^ count type
cr curve1 temperature name s^ count type ." = "
curve1 temperature value s@ f.
curve1 temperature unit s^ count type
cr curve1 angle name s^ count type ." = "
curve1 angle value s@ f.
curve1 angle unit s^ count type
cr ." data follows:"
20 0 do cr
i curve1 time s@ . space
i curve1 counts s@ .
loop
cr
;